package com.xpec.c4.codec;

import java.lang.reflect.Array;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.xpec.c4.codec.amf3.Amf3Codec;
import com.xpec.c4.codec.h2o.CodedInfo;
import com.xpec.c4.codec.h2o.Debug;
import com.xpec.c4.codec.h2o.H2oCodec;
import com.xpec.c4.codec.marshalling.MarshallingCodec;
import com.xpec.c4.message.MessageTypes;
import com.xpec.c4.net.codec.CodecExtendEx;
import com.xpec.c4.net.codec.ManualCodec;
import com.xpec.c4.net.codec.ZipCompressCodecExtend;
import com.xpec.c4.service.message.BasicMessage;

/**
 * AMF3的编解码工具
 * 
 * @author lipeilin
 * @2011-12-1 上午11:25:49
 * 
 */
public class CodecUtility {

	private static final Log log = LogFactory.getLog(CodecUtility.class);

	/**
	 * 编码类型
	 */
	public static final byte CODEC_TYPE_MANUAL = 0;
	public static final byte CODEC_TYPE_AMF3 = 1;
	public static final byte CODEC_TYPE_H2O = 2;
	public static final byte CODEC_TYPE_MARSHALLING = 3;

	/**
	 * 默认编码
	 */
	public static byte CODEC_TYPE_DEFAULT = CODEC_TYPE_H2O;

	/**
	 * amf3编码器
	 */
	private static final ThreadLocal<Amf3Codec> codec = new ThreadLocal<Amf3Codec>();

	/**
	 * h2o编码器
	 */
	private static H2oCodec h2oCodec = new H2oCodec();

	/**
	 * 需要用h2o编码方式，需要在这个列表中添加
	 */
	private static HashSet<Integer> h2oProtocolList = new HashSet<Integer>();

	/**
	 * 需要用amf3编码方式，需要在这个列表中添加
	 */
	private static HashSet<Integer> amf3ProtocolList = new HashSet<Integer>();

	/**
	 * 仅用于server消息
	 */
	private static HashSet<Integer> marshallingProtocolList = new HashSet<Integer>();

	private static CodecExtendEx extend = new ZipCompressCodecExtend();

	private static MarshallingCodec marshallingCodec = new MarshallingCodec();

	/**
	 * 把对象编码成字节数组
	 * 
	 * @param obj
	 * @return
	 * 
	 * @2011-11-30 下午06:37:47
	 */
	public static byte[] encodeByte(Object obj, int messageType) {

		try {
			byte[] bb = null;
			byte codecType = -1;

			// 手动编码
			if (obj instanceof ManualCodec) {
				bb = ((ManualCodec) obj).encode();
				codecType = CODEC_TYPE_MANUAL;

			} else {
				// 需要区分amf3或h2o
				// 如果没有在例外（h2oProtocolList或amf3ProtocolList）中存在，则使用默认编码。
				if (marshallingProtocolList.contains(messageType)) {
					bb = marshallingCodec.encodeEx(obj);
					codecType = CODEC_TYPE_MARSHALLING;
				} else if (CODEC_TYPE_DEFAULT == CODEC_TYPE_AMF3) {
					if (h2oProtocolList.contains(messageType)) {
						bb = h2oCodec.encodeEx(obj);
						codecType = CODEC_TYPE_H2O;
					} else {
						bb = getAmf3Codec().encodeEx(obj);
						codecType = CODEC_TYPE_AMF3;
					}
				} else {
					if (amf3ProtocolList.contains(messageType)) {
						bb = getAmf3Codec().encodeEx(obj);
						codecType = CODEC_TYPE_AMF3;
					} else {
						bb = h2oCodec.encodeEx(obj);
						codecType = CODEC_TYPE_H2O;
					}
				}
			}

			byte[] bytes = new byte[bb.length + 1];
			bytes[0] = codecType;
			System.arraycopy(bb, 0, bytes, 1, bb.length);

			return bytes;
		} catch (Exception e) {
			log.error("cannot encode obj:" + obj, e);
			throw new RuntimeException(e);
		}

	}

	/**
	 * 把对象编码成字节数组
	 * 
	 * @param obj
	 * @return
	 * 
	 * @2011-11-30 下午06:37:47
	 */
	public static Object decodeByte(byte[] bytes) {

		try {
			int type = bytes[0];
			byte[] bb = new byte[bytes.length - 1];
			System.arraycopy(bytes, 1, bb, 0, bb.length);

			switch (type) {
			case CODEC_TYPE_MANUAL:
				return bb;
			case CODEC_TYPE_AMF3:
				return getAmf3Codec().decodeByte(bb);
			case CODEC_TYPE_H2O:
				return h2oCodec.decodeByte(bb);
			case CODEC_TYPE_MARSHALLING:
				return marshallingCodec.decodeByte(bb);
			default:
				throw new RuntimeException("unknown encode type:" + type);
			}
		} catch (Exception e) {
			log.error("cannot decode obj", e);
			throw new RuntimeException(e);
		}

	}

	/**
	 * 
	 * @param bytes
	 * @param obj
	 * @param types
	 * @return
	 */
	public static Object h2oArrayTransfer(byte[] bytes, Object obj, Class<?>[] types) {
		if (bytes != null && types.length > 0 && bytes[0] == CODEC_TYPE_H2O
				&& List.class.isAssignableFrom(types[0]) && obj != null && obj.getClass().isArray()) {
			List list = new ArrayList();
			int size = Array.getLength(obj);
			for (int j = 0; j < size; j++) {
				list.add(Array.get(obj, j));
			}
			return list;
		} else {
			return obj;
		}
	}

	/**
	 * 送至client之前處理: 編碼+壓縮
	 */
	public static byte[] contentEncode(Object content, int messageType) {

		boolean compress = false;
		if (content instanceof BasicMessage && ((BasicMessage) content).isCompress() == true) {
			compress = true;
		}

		byte[] bb = null;
		byte codecType = -1;

		try {

			// 手动编码
			if (content instanceof ManualCodec) {
				bb = ((ManualCodec) content).encode();
				codecType = CODEC_TYPE_MANUAL;
			} else {
				// 需要区分amf3或h2o
				// 如果没有在例外（h2oProtocolList或amf3ProtocolList）中存在，则使用默认编码。
				if (marshallingProtocolList.contains(messageType)) {
					bb = marshallingCodec.encodeEx(content);
					codecType = CODEC_TYPE_MARSHALLING;
				} else if (CODEC_TYPE_DEFAULT == CODEC_TYPE_AMF3) {
					if (h2oProtocolList.contains(messageType)) {
						bb = h2oCodec.encodeEx(content);
						codecType = CODEC_TYPE_H2O;
					} else {
						bb = getAmf3Codec().encodeEx(content);
						codecType = CODEC_TYPE_AMF3;
					}
				} else {
					if (amf3ProtocolList.contains(messageType)) {
						bb = getAmf3Codec().encodeEx(content);
						codecType = CODEC_TYPE_AMF3;
					} else {
						bb = h2oCodec.encodeEx(content);
						codecType = CODEC_TYPE_H2O;
					}
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

		if (bb == null)
			return null;

		try {
			byte[] bytes = new byte[bb.length + 1];
			bytes[0] = codecType;
			System.arraycopy(bb, 0, bytes, 1, bb.length);

			ByteBuffer buffer = extend.execute(bytes, compress);
			buffer.flip();

			return buffer.array();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return null;
	}

	/**
	 * 
	 * @return
	 */
	private static Codec getAmf3Codec() {

		Amf3Codec c = codec.get();

		if (c == null) {
			c = new Amf3Codec();
			codec.set(c);
		}

		return c;
	}

	/**
	 * 注册需要用到h2o编码方式的协议
	 */
	public static void registerH2oMessageType() {
		// h2oProtocolList.add(MessageTypes.S_TEST);
		// h2oProtocolList.add(MessageTypes.S_ACCOUNT_MESSAGE);
		// h2oProtocolList.add(MessageTypes.S_ACCOUNT_CHARACTER_LIST_RESPONSE);
		// h2oProtocolList.add(MessageTypes.S_ACCOUNT_CHARACTER_CREATE_SUCCESS);
		// h2oProtocolList.add(MessageTypes.S_ACCOUNT_CHARACTER_LOGIN_RESPONSE);
		// h2oProtocolList.add(MessageTypes.S_ACCOUNT_CHARACTER_CREATE_RESPONSE);
		// h2oProtocolList.add(MessageTypes.S_GATEWAY_CODE_REQUEST);
		// h2oProtocolList.add(MessageTypes.S_ACCOUNT_GATEWAY_LOADINGINFO);
		// h2oProtocolList.add(MessageTypes.S_OTHER_OBJECT_ENTER);
	}

	/**
	 * 注册需要用到marshalling编码方式的协议
	 */
	public static void registerMarshallingMessageType() {
		marshallingProtocolList.add(MessageTypes.CREATE_ACCOUNT_INFO);
		marshallingProtocolList.add(MessageTypes.QUERY_ACCOUNT_INFO);
		marshallingProtocolList.add(MessageTypes.UPDATE_ACCOUNT_INFO);
		marshallingProtocolList.add(MessageTypes.S_DATA_RESPONSE);
		marshallingProtocolList.add(MessageTypes.CREATE_PLAYER_INFO);
		marshallingProtocolList.add(MessageTypes.GET_PLAYER_LIST_BY_GUID);
		marshallingProtocolList.add(MessageTypes.QUERY_PLAYER_INFO_BY_GUID);
		marshallingProtocolList.add(MessageTypes.UPDATE_PLAYER_INFO);
		marshallingProtocolList.add(MessageTypes.UPDATE_PLAYER_MONEY);
		marshallingProtocolList.add(MessageTypes.UPDATE_PLAYER_ITEM);
		marshallingProtocolList.add(MessageTypes.UPDATE_PLAYER_MONEY_ITEM);
		// marshallingProtocolList.add(MessageTypes.SEND_SERVER_INFO);
		// marshallingProtocolList.add(MessageTypes.SESSION_CONTEXT_CHANGE);
		// marshallingProtocolList.add(MessageTypes.USERID_SESSIONID_SYNCHRO);
		marshallingProtocolList.add(MessageTypes.SESSION_CLOSE);
		// marshallingProtocolList.add(MessageTypes.SYNC_RETURN);
		// marshallingProtocolList.add(MessageTypes.S_SAVE_CAMP_SESSION_REQUEST);
		// marshallingProtocolList.add(MessageTypes.S_REMOVE_CAMP_SESSION_REQUEST);
		marshallingProtocolList.add(MessageTypes.S_LOGIN_VERIFYCODE_REQUEST);
		marshallingProtocolList.add(MessageTypes.S_LOGIN_VERIFYCODE_RESPONSE);
		marshallingProtocolList.add(MessageTypes.S_SESSION_CLOSE_NOTIFY);

		/** DCLite用 **/
		marshallingProtocolList.add(MessageTypes.S_CENTRAL_REQUEST);
		marshallingProtocolList.add(MessageTypes.S_CENTRAL_RESPONSE);

	}

	/**
	 * 注册需要用到amf3编码方式的协议
	 */
	public static void registerAMF3MessageType() {
		// amf3ProtocolList.add(MessageTypes.S_GATEWAY_CODE_REQUEST);
		// amf3ProtocolList.add(MessageTypes.S_ACCOUNT_CHARACTER_LOGIN_RESPONSE);
		// amf3ProtocolList.add(MessageTypes.S_ACCOUNT_CHARACTER_CREATE_RESPONSE);
		// amf3ProtocolList.add(MessageTypes.S_ACCOUNT_CHARACTER_LIST_RESPONSE);

	}

	private static void registerH2oClass(int num, Class<?> clz) throws Exception {
		CodedInfo.registClass(clz, num);
	}

	/**
	 * 注册通讯用到的类 顺序要与client统一。
	 * 这些是client和server用到的
	 * server 與 client 之間收送消息 class 都註冊在這邊
	 */
	private static void registerH2o() throws Exception {
		registerH2oClass(1, com.xpec.c4.game.utility.GUID.class);

		// 共用
		registerH2oClass(50, com.ms.game.common.message.MoudleProcessErrorResponse.class);
		registerH2oClass(51, com.ms.game.slot.base.SeatVerifyInfo.class);
		registerH2oClass(52, com.xpec.c4.service.group.transportlayer.SyncModuleInfosMessage.class);
		registerH2oClass(53, com.ms.service.module.commonsettings.SUpdateCommonSettingsMessage.class);
		registerH2oClass(54, com.ms.service.module.commonsettings.CommonSettings.class);
		registerH2oClass(55, com.ms.service.module.commonsettings.CommonSendGiftSetting.class);
		registerH2oClass(56, com.ms.service.module.commonsettings.CommonDoubleNameSetting.class);
		registerH2oClass(57, com.ms.service.module.commonsettings.CommonAccountLoginBlockIPSetting.class);
		registerH2oClass(58, com.ms.service.module.commonsettings.CommonPurchaseLimitSetting.class);
		registerH2oClass(60, com.ms.service.module.commonsettings.CommonSendItemSetting.class);
		registerH2oClass(61, com.ms.service.module.commonsettings.DailyLoginSendSettings.class);
		registerH2oClass(62, com.ms.service.module.commonsettings.DailySendItemInfo.class);

		// login
		registerH2oClass(101, com.xpec.c4.message.login.CAccountCharacterCreateRequest.class);
		registerH2oClass(102, com.xpec.c4.message.login.CRobotAccountCharacterCreateRequest.class);
		registerH2oClass(104, com.xpec.c4.message.login.CAccountCharacterLoginRequest.class);
		registerH2oClass(105, com.xpec.c4.message.login.CAccountLoginRequest.class);
		registerH2oClass(106, com.xpec.c4.message.login.CAccountRobotLoginRequest.class);
		registerH2oClass(107, com.xpec.c4.message.login.SAccountCharacterListResponse.class);
		registerH2oClass(108, com.xpec.c4.message.login.SAccountCharacterLoginResponse.class);
		registerH2oClass(112, com.xpec.c4.message.login.SAccountLoginTokenInfo.class);
		registerH2oClass(113, com.xpec.c4.message.character.CharacterSampleInfo.class);
		registerH2oClass(114, com.xpec.c4.message.login.CUpdateLastLockPlayerAndDeviceTokenRequest.class);
		registerH2oClass(115, com.xpec.c4.message.login.SUpdateLastLockPlayerAndDeviceTokenResponse.class);
		registerH2oClass(116, com.xpec.c4.message.login.SAccountMessageData.class);

		// zone
		registerH2oClass(200, com.ms.service.module.zone.message.CPlayerLoginZoneRequest.class);
		registerH2oClass(201, com.ms.service.module.zone.message.SPlayerLoginZoneResult.class);
		registerH2oClass(202, com.ms.service.module.zone.message.SSimplePlayer.class);

		// zone - switch zone 2015/07/27 robert
		registerH2oClass(203, com.ms.service.module.zone.message.CPlayerSwitchZoneRequest.class);
		registerH2oClass(204, com.ms.service.module.zone.message.SPlayerSwitchZoneResponse.class);

		// lobby
		registerH2oClass(205, com.ms.game.lobby.message.SLobbyHallListResponse.class);
		registerH2oClass(206, com.ms.game.lobby.message.SHallTypeData.class);

		// zone 裡面傳送更新屬性清單給 client
		registerH2oClass(207, com.ms.player.message.SUpdatePlayerAttribute.class);
		registerH2oClass(208, com.ms.player.UpdateAttribute.class);
		registerH2oClass(209, com.ms.player.message.SUpdatePlayerZoneDataByAttributeList.class);
		// sendGift
		registerH2oClass(210, com.ms.game.sendgift.message.SendGiftRequest.class);
		registerH2oClass(211, com.ms.game.sendgift.message.SendGiftResponse.class);
		registerH2oClass(212, com.ms.game.sendgift.message.SendGiftNotifyMessage.class);
		registerH2oClass(213, com.ms.game.sendgift.message.SendGiftAllNotifyResponse.class);
		registerH2oClass(214, com.ms.game.sendgift.NotifyData.class);
		registerH2oClass(215, com.ms.game.lobby.message.SimpleKeepData.class);

		// zone 道具 1
		registerH2oClass(220, com.ms.player.message.SUpdatePlayerItem.class);
		registerH2oClass(221, com.ms.player.UpdateItem.class);
		registerH2oClass(222, com.ms.game.itembox.message.CUseItemRequest.class);
		registerH2oClass(223, com.ms.game.itembox.message.SUseSilentCardNotify.class);
		registerH2oClass(224, com.ms.game.itembox.message.CUseBroadcastCardRequest.class);
		registerH2oClass(225, com.ms.game.itembox.message.SBroadcastMessage.class);
		registerH2oClass(226, com.ms.game.itembox.message.SUseAnimationCardNotify.class);
		registerH2oClass(228, com.ms.game.itembox.message.CoinInfo.class);
		registerH2oClass(229, com.ms.game.invitefriend.bin.ItemInfo.class);
		registerH2oClass(230, com.ms.game.itembox.message.SpinRollItemDataResponse.class);
		registerH2oClass(231, com.ms.game.itembox.ItemSimpleData.class);
		registerH2oClass(232, com.ms.game.itembox.Item.class);
		registerH2oClass(233, com.ms.game.itembox.message.SZoneGetItemListResult.class);
		registerH2oClass(234, com.ms.game.itembox.message.SSimpleItem.class);
		registerH2oClass(235, com.ms.game.itembox.message.SItemRefineResult.class);
		registerH2oClass(236, com.ms.game.itembox.message.SGetAccountItemListResponse.class);
		registerH2oClass(237, com.ms.game.itembox.message.SGetItemFromAccountItemListResponse.class);

		// bank銀行
		registerH2oClass(240, com.ms.game.bank.message.BankRequest.class);
		registerH2oClass(241, com.ms.game.bank.message.BankResponse.class);
		registerH2oClass(242, com.ms.game.rebate.message.SRebateCoinDataMessage.class);
		registerH2oClass(243, com.ms.game.rebate.message.SRebateData.class);
		registerH2oClass(244, com.ms.game.rebate.message.SGetRebateCoinResponse.class);
		registerH2oClass(245, com.ms.game.bank.message.SBankPageResponse.class);
		registerH2oClass(246, com.ms.service.module.zone.message.SRechargePageResponse.class);
		registerH2oClass(247, com.ms.service.module.zone.message.CCashGoldTransactionDetailsRequest.class);
		registerH2oClass(248, com.ms.service.module.zone.message.SCashGoldTransactionDetailsResponse.class);
		registerH2oClass(249, com.ms.service.module.zone.message.SSimpleCashLog.class);
		registerH2oClass(251, com.ms.game.bank.message.BankBuyFeeRequest.class);
		registerH2oClass(252, com.ms.game.bank.message.BankBuyFeeResponse.class);

		// game lobby
		registerH2oClass(300, com.ms.game.lobby.message.SJackpotNotify.class);

		// characterInfo 玩家角色資料
		registerH2oClass(301, com.ms.game.characterInfo.message.CharacterInfoResponse.class);
		registerH2oClass(302, com.ms.game.characterInfo.GameLogInfo.class);
		registerH2oClass(303, com.ms.game.characterInfo.message.CharacterInfoRequest.class);
		registerH2oClass(304, com.ms.game.itembox.ItemField.class);

		// game lobby jackpot money
		registerH2oClass(305, com.ms.game.lobby.message.SGameJackPotBrocastResponse.class);
		registerH2oClass(306, com.ms.game.lobby.GameJackPotMoney.class);

		// characterInfo 玩家角色資料 邀請碼
		registerH2oClass(307, com.ms.game.invitefriend.message.CGetDownLineListRequest.class);
		registerH2oClass(308, com.ms.game.invitefriend.message.SGetDownLineListResponse.class);
		registerH2oClass(309, com.ms.game.invitefriend.message.DownLineInfo.class);
		registerH2oClass(310, com.ms.game.invitefriend.message.SGetCommissionDetailResponse.class);
		registerH2oClass(311, com.ms.game.invitefriend.message.ComSumInfo.class);
		registerH2oClass(312, com.ms.player.Player.class);
		registerH2oClass(313, com.ms.game.itembox.ItemBox.class);
		registerH2oClass(314, com.xpec.c4.game.character.PeriodSyncStatisInfo.class);

		// lobby 離線保留資料
		registerH2oClass(316, com.ms.game.lobby.message.SPlayerCheckOfflineKeepDataResponse.class);
		registerH2oClass(317, com.ms.game.lobby.message.CPlayerModifyOfflineKeepDataRequest.class);
		registerH2oClass(318, com.ms.game.lobby.message.SPlayerModifyOfflineKeepDataResponse.class);

		// 玩家資料更新清單
		registerH2oClass(319, com.ms.player.UpdateAttributeList.class);
		registerH2oClass(320, com.ms.player.UpdateItemList.class);

		// 領取自動回復幸運金
		registerH2oClass(322, com.ms.game.lobby.message.SGetAutoRecoverLuckyCoinResponse.class);

		// 每日登錄獎勵
		registerH2oClass(323, com.ms.game.lobby.message.ContinuiusRewardInfo.class);

		// 要求座位表
		registerH2oClass(324, com.ms.game.lobby.message.CLobbyHallMachinedataRequest.class);

		// 公告列表
		registerH2oClass(325, com.ms.game.lobby.bulletin.BulletinListInfo.class);

		// 公告列表資訊
		registerH2oClass(326, com.ms.game.lobby.bulletin.BulletinTitleInfo.class);

		// 公告內容
		registerH2oClass(327, com.ms.game.lobby.bulletin.BulletinInfo.class);

		// 邀請碼
		registerH2oClass(328, com.ms.game.invitefriend.message.SGetInviteCodeResponse.class);
		registerH2oClass(329, com.ms.game.invitefriend.message.SGetUplineInviteRewardRequest.class);

		// zone 小樂儲值
		registerH2oClass(330, com.ms.service.module.zone.message.SRobotAddCashMessage.class);

		// Bank 銀行明細
		registerH2oClass(331, com.ms.game.bank.message.CBankBookDetailsRequest.class);
		registerH2oClass(332, com.ms.game.bank.message.SBankBookDetailsResponse.class);
		registerH2oClass(333, com.ms.game.bank.message.SSimpleBankLog.class);

		// 邀請碼的細項
		registerH2oClass(334, com.ms.game.invitefriend.message.InviteCodeData.class);

		// 建立邀請碼帶的資料格是
		registerH2oClass(335, com.ms.game.invitefriend.message.AddInviteCodeData.class);

		// 回覆client取得的opID
		registerH2oClass(336, com.ms.service.module.zone.message.SOPIDResponse.class);

		// 經銷商邀請碼 - 修改經銷商設定 337 338
		registerH2oClass(337, com.ms.game.invitefriend.message.CModifySubDistributorCommSetting.class);
		registerH2oClass(338, com.ms.game.invitefriend.message.SModifySubDistributorCommSettingResponse.class);

		// 經銷商邀請碼 - 取得所有子經銷商
		registerH2oClass(339, com.ms.game.invitefriend.message.CGetSubDistributorsInfoRequest.class);
		registerH2oClass(340, com.ms.game.invitefriend.message.SGetSubDistributorsInfoResponse.class);
		registerH2oClass(341, com.ms.game.invitefriend.message.SubDistributorInfo.class);

		// 經銷商邀請碼 - 取得所有下線抽傭的資訊
		registerH2oClass(342, com.ms.game.invitefriend.message.CGetDownlineCommInfoRequest.class);
		registerH2oClass(343, com.ms.game.invitefriend.message.SGetDownlineCommInfoResponse.class);
		registerH2oClass(344, com.ms.game.invitefriend.message.DownlineCommInfo.class);
		registerH2oClass(345, com.ms.game.invitefriend.message.SDistributorSettingNotfiy.class);

		// zone 道具 2 450 ~ 499
		registerH2oClass(450, com.ms.game.itembox.container.GameCardChecker.class);
		registerH2oClass(453, com.ms.game.itembox.container.ItemExtraSettings.class);
		registerH2oClass(454, com.ms.game.itembox.message.SBroadCastGetItems.class);
		registerH2oClass(455, com.ms.game.itembox.message.CUseChangeNameCardRequest.class);
		registerH2oClass(456, com.ms.game.itembox.message.SUseChangeNameCardResponse.class);
		registerH2oClass(457, com.ms.game.itembox.container.ItemDrawInfo.class);
		registerH2oClass(458, com.ms.game.itembox.message.SBatchChangeGoldCoinCardResponse.class);

		// dc lite
		registerH2oClass(500,
				com.ms.service.module.datacenterlite.message.SDCLiteNotifySeatStatChangeRequest.class);
		registerH2oClass(501, com.ms.service.module.datacenterlite.GameKeepSeatData.class);

		// log spout
		registerH2oClass(600, com.ms.service.module.logspout.message.SLogSpoutMessage.class);

		// tmp cash 暫存錢包
		registerH2oClass(700, com.ms.service.module.zone.message.STmpCashUpdateNotify.class);
		registerH2oClass(701, com.ms.service.module.zone.message.CTmpCashTakeRequest.class);
		registerH2oClass(702, com.ms.service.module.zone.message.STmpCashTakeResult.class);

		// GameLobby 2
		registerH2oClass(1100, com.ms.game.lobby.message.GameActivitySettings.class);
		// 遊戲紀錄2
		registerH2oClass(1101, com.ms.game.characterInfo.message.CGetItemTypeGameRecordRequest.class);

		// 每日登入送東西
		registerH2oClass(1104, com.ms.service.module.zone.message.DailyLoginSendResponse.class);

		// 停權名單
		registerH2oClass(1105,
				com.ms.game.lobby.terminatedaccountlist.message.CGetTerminatedAccountListRequest.class);
		registerH2oClass(1106,
				com.ms.game.lobby.terminatedaccountlist.message.SGetTerminatedAccountListResponse.class);
		registerH2oClass(1107, com.ms.game.lobby.terminatedaccountlist.message.TerminatedAccountData.class);

		// 付費相關 1400
		registerH2oClass(1400, com.ms.game.purchase.message.SPurchaseDataListResult.class);
		registerH2oClass(1401, com.ms.game.purchase.bin.PurchaseItemInfo.class);
		registerH2oClass(1402, com.ms.game.purchase.message.SPurchaseDataListResult_IOS.class);
		registerH2oClass(1403, com.ms.game.purchase.bin.PurchaseItemInfoIOS.class);

		// 離線 spin 結果
		registerH2oClass(1700, com.ms.game.offlineSpin.OfflineSpinResultData.class);
		registerH2oClass(1701, com.ms.game.offlineSpin.message.SOfflineSpinResultGetResult.class);

		// GMTool 2000
		registerH2oClass(2002, com.ms.game.gmtool.WhiteListInfo.class);
		registerH2oClass(2003, com.ms.game.lobby.bulletin.BulletinModelInfo.class);
		registerH2oClass(2004, com.ms.game.lobby.bulletin.BullentinAllListInfo.class);
		registerH2oClass(2007, com.ms.game.forciblyBulletin.ForciblyBulletinInfo.class);
		registerH2oClass(2008, com.ms.game.forciblyBulletin.ForciblyBulletinContainer.class);
		registerH2oClass(2009, com.ms.game.gmtool.PlayerDisableData.class);
		registerH2oClass(2010, com.ms.game.gmtool.message.SGmtoolServerShutdownCountdownNotify.class);
		registerH2oClass(2011, com.ms.game.gmtool.message.SGmtoolServerShutdownCountdownNotifyToClient.class);
		registerH2oClass(2012, com.ms.game.gmtool.message.GMChatServiceRequest.class);
		registerH2oClass(2014, com.ms.game.gmtool.message.SBanTimeMessage.class);
		registerH2oClass(2015, com.ms.game.gmtool.message.SUpdatePlayerSwitchList.class);
		registerH2oClass(2016, com.ms.game.gmtool.message.SGmtoolGetRealTimePlayerListData.class);
		registerH2oClass(2017, com.ms.game.gmtool.message.SExtendPlayerKeepSeatTimeRequest.class);
		registerH2oClass(2018, com.ms.game.gmtool.message.SGmtoolChangeGameModuleState.class);
		registerH2oClass(2020, com.ms.game.gmtool.message.SGmtoolUpdateItemInfos.class);
		registerH2oClass(2021, com.ms.game.gmtool.message.SGmtoolKickAllConnectionNotify.class);
		registerH2oClass(2022, com.ms.game.gmtool.async.IapBillingBuyFeeAsync.class);

		// Account 3000
		registerH2oClass(3000, com.ms.service.module.account.message.SAccountCashBonusMessage.class);

		// Billing 3100
		registerH2oClass(3100, com.ms.game.gmtool.message.CApplyIAPOrderIDRequest.class);
		registerH2oClass(3101, com.ms.game.gmtool.message.CApplyIAPVerifyRequest.class);
		registerH2oClass(3102, com.ms.game.gmtool.message.SApplyIAPOrderIDResponse.class);
		registerH2oClass(3103, com.ms.game.gmtool.message.SApplyIAPVerifyResponse.class);
		registerH2oClass(3104, com.ms.game.gmtool.message.CAppleIapVerifyRequest.class);
		registerH2oClass(3105, com.ms.game.gmtool.message.SAppleIapVerifyRsponse.class);
		registerH2oClass(3106, com.ms.game.gmtool.message.CAppleIapAskCashRequest.class);
		registerH2oClass(3107, com.ms.game.gmtool.message.SAppleIapAskCashResponse.class);
		registerH2oClass(3108, com.ms.game.gmtool.message.SIapAskCashResponse.class);

		// ********************************
		// 分析統計模块 4
		// ********************************

		// 日常收支
		registerH2oClass(4000, com.ms.game.characterInfo.message.DailyExchangeRequest.class);
		registerH2oClass(4001, com.ms.game.characterInfo.message.DailyExchangeResponse.class);
		registerH2oClass(4002, com.ms.game.characterInfo.DailyExchange.class);

		// jackpot
		registerH2oClass(7000, com.ms.service.module.zone.message.SGameJackPotLockResquest.class);
		registerH2oClass(7001, com.ms.service.module.zone.message.SGameJackPotLockResponse.class);

		registerH2oClass(7002, com.ms.service.module.zone.message.SGameJackPotUnLockResquest.class);
		registerH2oClass(7003, com.ms.service.module.zone.message.SGameJackPotUnLockResponse.class);

		// mgdh - doorman 8000
		registerH2oClass(8048, com.ms.game.mgdh.message.SDoorManCancelOfflineKeepDataRequest.class);
		registerH2oClass(8049, com.ms.game.mgdh.message.SDoorManCancelOfflineKeepDataBackRequest.class);

		// ..........
		registerH2oClass(9871, com.xpec.c4.message.zone.SPlayerLogoutZone.class);
		registerH2oClass(9942, com.xpec.c4.service.module.gateway.SetSessionStatus.class);
		registerH2oClass(9943, com.xpec.c4.service.module.h5gateway.H5SetSessionStatus.class);

		// 系統使用
		registerH2oClass(9908, com.xpec.c4.service.group.transportlayer.SessionCloseNotify.class);
		registerH2oClass(9909, com.xpec.c4.message.login.SAccountLoginRequest.class);
		registerH2oClass(9823, com.xpec.c4.service.module.gateway.CGatewayLoadingInfo.class);
		registerH2oClass(9824, com.ms.service.module.account.message.SSessionCloseNotify.class);
		registerH2oClass(9825, com.ms.service.module.account.message.SCharacterLoginNotify.class);

		registerH2oClass(10001, com.xpec.c4.service.group.transportlayer.GroupMember.class);
		registerH2oClass(10002, com.xpec.c4.message.ContextStatus.class);
		registerH2oClass(10003, com.xpec.c4.service.module.gateway.CGatewayCodeRequest.class);
		registerH2oClass(10004, com.ms.service.module.common.message.SPlayerCommonInfo.class);

		// debug command
		registerH2oClass(11000, com.ms.game.lobby.message.LobbyDebugCmdToModuleRequest.class);

		// slot basic message
		registerH2oClass(12000, com.ms.game.slot.base.message.SlotBasicDMMessageRequest.class);
		registerH2oClass(12001, com.ms.game.slot.base.message.SlotBasicGameMessageRequest.class);
		registerH2oClass(12002, com.ms.game.slot.base.message.SSlotCommonDmSeatPlayerInfoRequest.class);
		registerH2oClass(12003, com.ms.game.slot.base.message.SGmtoolCleanGameSeatStatusRequest.class);
		registerH2oClass(12004, com.ms.game.slot.base.message.SGmtoolCleanDoormanSeatStatusRequest.class);
		registerH2oClass(12005, com.ms.game.slot.base.message.CSlotCommonDmSetRecvSeatUpdatePageRequest.class);
		registerH2oClass(12006, com.ms.game.slot.base.message.CSlotCommonUseGameCardRequest.class);
		registerH2oClass(12007, com.ms.game.slot.base.message.SSlotCommonUseGameCardResponse.class);

		// jp module
		registerH2oClass(13000, com.ms.game.jackpot.message.CGetGameJackPotMoney.class);
		registerH2oClass(13001, com.ms.game.jackpot.message.SGameNotifyJackpotMoney.class);
		registerH2oClass(13002, com.ms.game.jackpot.message.SGameJackpotCacheResquest.class);
		registerH2oClass(13003, com.ms.game.jackpot.JackPotMoneyData.class);
		registerH2oClass(13004, com.ms.game.jackpot.message.SGetGameJackpotMoneyResponse.class);
		registerH2oClass(13005, com.ms.game.jackpot.message.SGameBrocastJackpotMoneyResponse.class);
		registerH2oClass(13006, com.ms.game.jackpot.message.SBasicGameReturnJPMoneyRequest.class);

		// robot module

		// 超級踢人
		registerH2oClass(14201, com.ms.service.module.datacenterlite.CancelKeepDataOption.class);

		// module 管理
		registerH2oClass(15001, com.xpec.c4.service.module.message.ModuleStatus.class);

		// slot 共用訊息
		// client use or listen
		registerH2oClass(16001, com.ms.game.slot.base.message.SlotGameDoSeatVerifyRequest.class);
		registerH2oClass(16002, com.ms.game.slot.base.message.SlotGameAsyncDoSeatDataRequest.class);
		// client use or listen
		registerH2oClass(16003, com.ms.game.slot.base.message.SlotGameDoSeatVerifyResponse.class);
		registerH2oClass(16004, com.ms.game.slot.base.message.SlotGameLeaveBackRequest.class);
		// client use or listen
		registerH2oClass(16005, com.ms.game.slot.base.message.SlotGameLeaveRequest.class);
		// client use or listen
		registerH2oClass(16006, com.ms.game.slot.base.message.SlotGameLeaveResponse.class);
		registerH2oClass(16007, com.ms.game.slot.base.DMBasicSeatInfo.class);
		registerH2oClass(16008, com.ms.game.slot.base.SlotHistoryBase.class);
		registerH2oClass(16009, com.ms.game.slot.base.message.SDMVerifyExpriedRequest.class);
		// client use or listen
		registerH2oClass(16010, com.ms.game.slot.base.message.SDMSeatStatChangeRequest.class);
		// client use or listen
		registerH2oClass(16011, com.ms.game.slot.base.message.SDMDoSeatRequest.class);
		registerH2oClass(16012, com.ms.game.slot.base.message.SDMVerifyExpriedTableUserRequest.class);
		registerH2oClass(16013, com.ms.game.slot.base.message.STableGameAsynDoSeatDataRequest.class);
		// client use or listen
		registerH2oClass(16014, com.ms.game.slot.base.table.DMBasicTableUser.class);
		// client use or listen
		registerH2oClass(16015, com.ms.game.slot.base.SlotOptionBase.class);

		// slot 共用類別
		registerH2oClass(16016, com.ms.game.slot.base.Bouns.class);
		registerH2oClass(16017, com.ms.game.slot.base.Way.class);
		registerH2oClass(16018, com.ms.game.slot.base.SlotBetInfo.class);
		registerH2oClass(16019, com.ms.game.slot.base.SlotBasicRookiePourWaterInfo.class);

		registerH2oClass(16020, com.ms.game.slot.base.message.SSlotDMMachineListResponse.class);
		registerH2oClass(16021, com.ms.game.slot.base.message.SGainRateData.class);

		// ANALYSIS & ANALYSIS GROUP
		registerH2oClass(18001, com.ms.service.module.analysis.message.PlayerEnterSeatData.class);
		registerH2oClass(18002, com.ms.service.module.analysis.message.MachineData.class);
		registerH2oClass(18003, com.ms.service.module.analysis.message.PlayerBetData.class);
		registerH2oClass(18004, com.ms.service.module.analysisgroup.message.SGameRnERequestData.class);
		registerH2oClass(18005, com.ms.service.module.analysisgroup.message.SPlayerRnERequestData.class);
		registerH2oClass(18006, com.ms.service.module.analysisgroup.message.SCoinExpenditureData.class);
		registerH2oClass(18007, com.ms.service.module.analysisgroup.message.SCheckSendGiftIntervalTimeData.class);
		registerH2oClass(18008, com.ms.service.module.analysisgroup.message.SItemChangeData.class);
		registerH2oClass(18009, com.ms.service.module.analysis.message.SRealTimePlayerCountRequest.class);
		registerH2oClass(18010, com.ms.service.module.analysis.message.SRealTimePlayerCountResponse.class);
		registerH2oClass(18013, com.ms.service.module.analysisgroup.message.SUsedCoinCardDetailData.class);

		// 客戶端回報功能
		registerH2oClass(20001, com.ms.service.module.zone.message.SClientReportRequest.class);
		registerH2oClass(20002, com.ms.service.module.analysis.message.ClientReportData.class);

		// player spin 金錢記錄
		registerH2oClass(25001, com.xpec.c4.game.spinMoneyRecorder.SpinMoneyRecorder.class);
		registerH2oClass(25002, com.xpec.c4.game.spinMoneyRecorder.db.SpinMoneyRecordLogModel.class);

		registerH2oClass(28015, com.ms.game.gameActivity.container.GameActivityTimeContainer.class);
		
		//百家樂 2200
		registerH2oClass(2200, com.ms.service.module.baccarat.BacrBetInfo.class);
		registerH2oClass(2201, com.ms.service.module.baccarat.BacrGameResult.class);
		registerH2oClass(2202, com.ms.service.module.baccarat.BacrCard.class);
		registerH2oClass(2203, com.ms.service.module.baccarat.message.SBacrInitData.class);
		registerH2oClass(2204, com.ms.service.module.baccarat.message.SBacrDiscardStart.class);
		registerH2oClass(2205, com.ms.service.module.baccarat.message.SBacrPlayerBetStart.class);
		registerH2oClass(2206, com.ms.service.module.baccarat.message.CBacrPlayerBetRequest.class);
		registerH2oClass(2207, com.ms.service.module.baccarat.message.SBacrPlayerBetResult.class);
		registerH2oClass(2208, com.ms.service.module.baccarat.message.SBacrBroadcastPlayerBetInfo.class);
		registerH2oClass(2209, com.ms.service.module.baccarat.message.SBacrDealtStart.class);
		registerH2oClass(2210, com.ms.service.module.baccarat.message.SBacrOpenCardStart.class);
		registerH2oClass(2211, com.ms.service.module.baccarat.message.SBacrHitsStart.class);
		registerH2oClass(2212, com.ms.service.module.baccarat.message.SBacrCalculateScoreStart.class);
		registerH2oClass(2213, com.ms.service.module.baccarat.message.BacrStepStartMsgBase.class);
		registerH2oClass(2214, com.ms.service.module.baccarat.message.SBacrShuffleStart.class);
		registerH2oClass(2215, com.ms.service.module.baccarat.message.SBacrRobotBetRequest.class);
		registerH2oClass(2216, com.ms.service.module.baccarat.message.SBacrDoormanAsyncHistoryData.class);
		registerH2oClass(2217, com.ms.service.module.baccarat.message.SBacrDoormanTableGameResultUpdate.class);
		registerH2oClass(2218, com.ms.service.module.baccarat.message.SBacrWaitToStart.class);
		registerH2oClass(2219, com.ms.service.module.baccarat.message.SBacrIdleStart.class);
		registerH2oClass(2220, com.ms.service.module.baccarat.message.SBacrActivityCombosData.class);
		registerH2oClass(2221, com.ms.service.module.baccarat.db.BacrActivityCombosInfoModel.class);
		registerH2oClass(2222, com.ms.service.module.baccarat.bin.BacrTableSettingInfo.class);
		registerH2oClass(2223, com.ms.service.module.baccarat.message.BacrSeatUpdateInfo.class);

		registerH2oClass(2250, com.ms.service.module.baccarat.message.SBacrDoSeatResponse.class);
		registerH2oClass(2251, com.ms.service.module.baccarat.message.SBacrDoSeatVerify.class);
		registerH2oClass(2252, com.ms.service.module.baccarat.message.SBacrTableUpdateResponse.class);
		registerH2oClass(2253, com.ms.service.module.baccarat.message.SBarcHallListResponse.class);
		registerH2oClass(2254, com.ms.service.module.baccarat.BacrTableOption.class);
		registerH2oClass(2255, com.ms.service.module.baccarat.BacrUserInfo.class);
	}

	/**
	 * 注册通讯用到的类 顺序要与client统一。
	 */
	public static void registerH2oClass() throws Exception {
		registerH2o();
		CodedInfo.registerFields();

		// Debug.printRegisterClass();
		// Debug.printRegisterFields();
	}

	/**
	 * 调用此方法打印h2o class，用于跟client验证。
	 */
	private static void printRegistedH2oClientClass() throws Exception {
		registerH2o();
		CodedInfo.registerFields();
		Debug.printRegisterClass();
		Debug.printRegisterFields();
	}

	public static void addAmf3Protocol(int type) {
		amf3ProtocolList.add(type);
	}

	/**
	 * 獲得moduleID，解String用
	 */
	public static Object h2oDecode(ByteBuffer buffer) {
		byte[] bytes = new byte[buffer.remaining()];
		int beginPosition = buffer.position();
		buffer.get(bytes);
		Object result = null;
		int used = 0;
		try {
			result = h2oCodec.decodeByte(bytes);
			used = (int) readPosition(bytes) + 2;
		} catch (Exception e) {
			e.printStackTrace();
		}

		// 讀取完moduleID後要重設buffer座標
		buffer.position(used + beginPosition);

		return result;
	}

	/**
	 * 解讀string用到的長度，轉出long
	 */
	private static long readPosition(byte[] buffer) throws Exception {
		int shift = 0;
		int position = 1; // 第一個位跳過是type型別
		long result = 0;
		while (shift < 64) {
			final byte b = buffer[position++];
			result |= (long) (b & 0x7F) << shift;
			if ((b & 0x80) == 0) {
				return result;
			}
			shift += 7;
		}
		throw new Exception("malformed varint 64");
	}
	
	/**
	 * 编码moduleID
	 */
	public static byte[] h2oEncode(String moduleID) {
		try {
			return h2oCodec.encodeByte(moduleID);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public static void main(String[] args) throws Exception {
		registerH2oClass();
		printRegistedH2oClientClass();

		// byte[] bytes2 = Debug
		// .transferToBytes("2 e 4e 2 c 1 1 e 9 8 9 8 63 61 6d 70 5f 30 30 32 1c 4 4 9 f 65 71 75 69 70 6d 65 6e 74 5f 31 30 30 30 37 19 f 65 71 75 69 70 6d 65 6e 74 5f 31 30 30 30 31 29 f 65 71 75 69 70 6d 65 6e 74 5f 31 30 30 31 33 39 f 65 71 75 69 70 6d 65 6e 74 5f 31 30 30 30 32 2c 4 4 9 12 70 6f 72 74 72 61 69 74 5f 68 61 69 72 5f 30 30 32 33 19 12 70 6f 72 74 72 61 69 74 5f 66 61 63 65 5f 31 30 30 35 29 12 70 6f 72 74 72 61 69 74 5f 66 61 63 65 5f 32 30 30 30 39 12 70 6f 72 74 72 61 69 74 5f 66 61 63 65 5f 35 30 30 31 3a 4 4d 41 4c 45 49 18 70 6c 61 79 65 72 5f 35 34 34 35 32 30 31 59 43 41 76 38 46 35 31 35 34 55 e 69 5 66 69 6e 61 6c 7a 6 4b 4e 49 47 48 54 26 fa a0 b1 ab d6 26");
		// Object obj2 = decodeByte(bytes2);
		// System.out.println(obj2);

		// System.out.println(System.currentTimeMillis());
		// System.out.println(new Date(1327144894480L));

		// System.out.println(Integer.MIN_VALUE - 100);
		// System.out.println(" : " + ((Integer.MIN_VALUE - 100)&~0xff));
		// long value = -1327144894480L;
		// while (true) {
		// if ((value & ~0x7F) == 0) {
		// System.out.println("last put : " + (byte) value);
		// break;
		// } else {
		// System.out.print("put : " + ((value & 0x7F) | 0x80));
		// value >>>= 7;
		// System.out.println(" | val : " + value);
		// }
		// }
	}
}
